
from PIL import Image, ImageDraw, ImageFont
from meiduo_admin.settings import *
from django.http.response import HttpResponse
import random,io
from django.core.cache import cache
from rest_framework.views import APIView
from rest_framework.response import Response
import re
from django.contrib.auth.hashers import make_password
from .models import *
from urllib.parse import urlencode
import requests,uuid
from django.db import transaction
from rest_framework_jwt.settings import api_settings
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
from django.contrib.auth.backends import ModelBackend,UserModel
from django.db.models import Q
from django.core.mail import send_mail
from itsdangerous import TimedJSONWebSignatureSerializer
from rest_framework.permissions import IsAuthenticated,AllowAny



class UserPhoneLogin(ModelBackend):
    def authenticate(self, request, username=None, password=None, **kwargs):
        #判断username是否存在
        if username is None:
            #要先导入Usermodel
            username = kwargs.get(UserModel.USERNAME_FIELD)
        try:
            #查询数据库，获取当前username的用户信息
            # user = UserModel._default_manager.get_by_natural_key(username)
            #传过来的username有可能是手机号
            user = MyUser.objects.get(Q(username=username) | Q(phone=username))
        #用户不存在时抛出错误
        except UserModel.DoesNotExist:
            # Run the default password hasher once to reduce the timing
            # difference between an existing and a nonexistent user (#20760).
            UserModel().set_password(password)
        else:
            #用户有了，检查password
            if user.check_password(password) and self.user_can_authenticate(user):
                return user
def send_alysms(phone,sms_code):
    AK = 'LTAI4FbvMorCdSAkn39Cbkjb'
    SK = 'XLzo7Jg3SyxGszljv5hqHXQUNN3777'

    client = AcsClient(AK, SK, 'cn-hangzhou')

    request = CommonRequest()
    request.set_accept_format('json')
    request.set_domain('dysmsapi.aliyuncs.com')
    request.set_method('POST')
    request.set_protocol_type('https') # https | http
    request.set_version('2017-05-25')
    request.set_action_name('SendSms')

    request.add_query_param('RegionId', "cn-hangzhou")
    request.add_query_param('PhoneNumbers', str(phone))
    request.add_query_param('SignName', "jiyunmd")
    request.add_query_param('TemplateCode', "SMS_185840404")
    request.add_query_param('TemplateParam', "{\"code\":code}")

    response = client.do_action(request)
    # python2:  print(response)
    print(str(response, encoding = 'utf-8'))



def generate_image_code(request, generate_image_id):
    '''
        本地图片验证码生成函数
    '''

    bgcolor = (random.randrange(20, 100), random.randrange(
        20, 100), random.randrange(20, 100))
    width = 110
    height = 40
    # 创建画面对象
    im = Image.new('RGB', (width, height), bgcolor)
    # 创建画笔对象
    draw = ImageDraw.Draw(im)
    # 调用画笔的point()函数绘制噪点
    for i in range(0, 100):
        xy = (random.randrange(0, width), random.randrange(0, height))
        fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
        draw.point(xy, fill=fill)
    # 定义验证码的备选值
    str = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
    # 随机选取4个值作为验证码
    rand_str = ''
    for i in range(0, 4):
        rand_str += str[random.randrange(0, len(str))]
    # 构造字体对象

    fonts_files = os.path.join(
        FONTS_DIRS, 'SourceCodePro-Bold.ttf')
    font = ImageFont.truetype(fonts_files, 30)
    # 构造字体颜色
    fontcolor1 = (255, random.randrange(0, 255), random.randrange(0, 255))
    fontcolor2 = (255, random.randrange(0, 255), random.randrange(0, 255))
    fontcolor3 = (255, random.randrange(0, 255), random.randrange(0, 255))
    fontcolor4 = (255, random.randrange(0, 255), random.randrange(0, 255))
    # 绘制4个字
    draw.text((5, 2), rand_str[0], font=font, fill=fontcolor1)
    draw.text((25, 2), rand_str[1], font=font, fill=fontcolor2)
    draw.text((50, 2), rand_str[2], font=font, fill=fontcolor3)
    draw.text((75, 2), rand_str[3], font=font, fill=fontcolor4)
    # 释放画笔
    del draw
    # 存入缓存，用于做进一步验证，并设置超时时间为10分组
    cache.set(generate_image_id,rand_str,60*10)

    buf = io.BytesIO()
    # 将图片保存在内存中，文件类型为png
    im.save(buf, 'png')
    # 将内存中的图片数据返回给客户端，MIME类型为图片png！
    return HttpResponse(buf.getvalue(), 'image/png')


class CheckCode(APIView):
    def post(self,request):
        data = request.data
        sms_code=data["sms_code"]
        uuid_=data["uuid_"]

        redis_code=cache.get(uuid_)

        if redis_code.lower() == sms_code.lower():
            return Response({"code":200})
        else:
            return Response({"code":500})


class UserView(APIView):
    def post(self,request):
        phone = request.data.get("phone")
        username = request.data.get("username")
        password = request.data.get("password")
        password1 = request.data.get("password1")

        if password != password1:
            data={
                "code":410,
                "msg":"如果两次密码不一致，请重试"
            }
            return  Response(data,status=200)
        phone_rul = r"1[\d]{10}$"
        phone_result =re.match(phone_rul,phone)

        if not phone_result:
            data = {
                "code": 411,
                "msg": "手机格式不对，请重试"
            }
            return Response(data, status=200)
        #生成密文密码
        pwd_hash = make_password(password)
        try:
            user = MyUser.objects.create(username=username,password=pwd_hash,phone=phone)
            print(user)
            return Response({"code":200,"msg":"注册成功"})
        except Exception as e:
            data={
                "code":500,
                "msg":"注册失败"
            }
            return Response(data,status=200)


# 重新用户登录返回函数
def jwt_response_payload_handler(token, user=None, request=None):
    '''
    :param token: jwt生成的token值
    :param user: User对象
    :param request: 请求
    '''
    return {
        'token': token,
        'user': user.username,
        'userid': user.id
    }


class WeiBoURLView(APIView):
    permission_classes = [AllowAny]
    def get(self,request):
        url="https://api.weibo.com/oauth2/authorize?"
        data={
            "client_id":str(WEIBO_APP_KEY),
            "response_type":"code",
            "redirect_uri":WEIBO_CALLBACK_URL
        }
        # weibo_url = url +"?client_id="+data["client_id"]+"&response_type="+data["response_type"]+"&redirect_uri="+data["redirect_uri"]
        # print(weibo_url)   #手动添加

        weibo_url = url+urlencode(data)   #导包添加
        print(weibo_url)
        return Response({'code':200,"url":weibo_url})

# def jwt_response_payload_handler(token, user=None, request=None):     #注释部分为回顾部分（登录）
#     '''
#     :param token: jwt生成的token值
#     :param user: User对象
#     :param request: 请求
#     '''
#     return {
#         'token': token,
#         'user': user.username,
#         'userid': user.id
#     }
#
#
# class WeiBoURLView(APIView):
#     def get(self,request):
#         url="https://api.weibo.com/oauth2/authorize?"
#         data={
#             "client_id":str(WEIBO_APP_KEY),
#             "response_type":"code",
#             "redirect_uri":WEIBO_CALLBACK_URL
#         }
#         # weibo_url = url +"?client_id="+data["client_id"]+"&response_type="+data["response_type"]+"&redirect_uri="+data["redirect_uri"]
#         # print(weibo_url)   #手动添加
#
#         weibo_url = url+urlencode(data)   #导包添加
#         print(weibo_url)
#         return Response({'code':200,"url":weibo_url})

class WeiBoCodeView(APIView):
    def get(self,request):
        code = request.query_params.get("code")

        if code:
            send_url="https://api.weibo.com/oauth2/access_token"
            send_data={
                "client_id":WEIBO_APP_KEY,
                "client_secret":WEIBO_SECRET,
                "grant_type":"authorization_code",
                "code":code,
                "redirect_uri":WEIBO_CALLBACK_URL
            }
            weibo_response= requests.post(url=send_url,data=send_data).json()
            # print(weibo_response["uid"])
            try:
                uid = weibo_response["uid"]
                uid_user = APPUID.objects.get(uid=uid)
                user=uid_user.users
                jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
                jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
                payload = jwt_payload_handler(user)
                token = jwt_encode_handler(payload)
                res_data = {
                    "code":200,
                    "token":token,
                    "username":uid_user.users.username,    # 取到它外键关联的数据
                    "id":uid_user.users.id
                }
                return Response(res_data,status=200)
            except:
                res_data={
                    "code":4004,
                    "msg":"本地没有这个用户的uid",
                    "uid":uid
                }
                return Response(res_data,status=200)


        else:
            return Response({"code":500,"msg":"未获取到"})


class BangUser(APIView):
    def post(self,request):
        username=request.data.get("username")
        password = request.data.get("password")
        phone = request.data.get("phone")
        uid = request.data.get("uid")

        #创建两个表里的数据,事务解决
        try:
            with transaction.atomic():
                # 创建一个还原点
                save_id = transaction.savepoint()
                try:
                    user = MyUser.objects.create(username=username,password=make_password(password),phone=phone)
                    user_uid = APPUID.objects.create(uid=uid,from_app=4,users=user)

                except:
                    # 回滚到还原点
                    transaction.savepoint_rollback(save_id)
                finally:
                    # 将事务提交
                    transaction.savepoint_commit(save_id)
                return Response({"code":200},status=200)
        except:
            return Response({"code":500},status=200)


class SMSCode(APIView):
    def get(self,request):
        phone=request.query_params.get("phone")
        phone_rul = r"1[\d]{10}$"
        phone_result = re.match(phone_rul, phone)
        if not phone_result:
            data = {
                "code": 419,
                "msg": "手机格式不对，请重试"
            }
            return Response(data, status=200)
        code = random.randint(100000,999999)
        print(code)
        send_alysms(phone,code)

        #向redis里存放数据
        cache.set(phone,code)
        data={
            "code":200,
            "msg":"发送成功"
        }
        return Response(data,status=200)

class SMSUserView(APIView):
    def post(self,request):
        phone = request.data.get("phone")
        password = request.data.get("password")
        code = request.data.get("code")

        if int(code) != int(cache.get(phone)):
            data={
                "code":4001,
                "msg":"验证码错误"
            }
        uuid_name = str(uuid.uuid4())
        try:
            user=MyUser.objects.create(username=uuid_name,password=make_password(password),phone=phone)
            data={
                "code":200,
                "msg":"成功"
            }
            return Response(data,status=200)
        except:
            data = {
                "code": 500,
                "msg": "失败，请重试"
            }
            return Response(data, status=200)

def bin_send_email(url,send_people):
    subject="密码找回"
    message="感谢使用美多商城，您现在使用的是找回密码功能，点击链接找回密码"
    from_email=EMAIL_FROM
    recipient_list=[send_people]
    res = send_mail(subject,message,from_email,recipient_list)
    return res

token_ser = TimedJSONWebSignatureSerializer(SECRET_KEY,3600)
class SendUserView(APIView):
    def get(self,request):
        email = request.query_params.get("email")
        print(email)
        if not email:
            data={
                "code":4005,
                "msg":"邮箱缺失，重新发送"
            }
            return Response(data,status=200)
        data={
            "email":email
        }
        token = token_ser.dumps(data).decode()
        url = "http://127.0.0.1:8080/#/reset_pwd?token = %s" % token
        res = bin_send_email(url,email)
        print(res)
        return Response({"code":200,"msg":"发送成功，注意查收"},status=200)

class PasswordChangeView(APIView):
    def post(self,request):
        token=request.data.get("token")
        password=request.data.get("password")
        password2=request.data.get("password2")

        if not all([token,password,password2]):
            data={
                "code":4005,
                "msg":"参数不齐全，请重试"
            }
            return Response(data,status=200)
        if password != password2:
            data={
                "code":4006,
                "msg":"两次密码不一致"
            }
            return Response(data,status=200)
        email_data=token_ser.loads(token)
        print(email_data)
        try:
            hash_pwd =make_password(password)
            MyUser.objects.filter(email=email_data["email"]).updata(password=hash_pwd)
            return Response({"code":200,"msg":"修改成功"})
        except:
            return Response({"code":500,"msg":"修改失败，请重试"})

